<template>
  <div class="chat-box">
    <div class="chat-window" ref="chatWindow">
      <div v-for="message in allMessage" class="message-cell">
        <div class="avator-box">
          <div class="avator" :class="`${message.role}-avator`"></div>
        </div>
        <div class="message-text">
          <div class="text" v-html="message.content"></div>
        </div>
      </div>
    </div>
    <div class="footer">
      <input type="text" class="message-input" placeholder="输入……" v-model="userMessage"
        @keydown.enter="sendMessage(userMessage)">
      <input type="button" value="发送" class="send-button" @click="sendMessage(userMessage)">
    </div>

  </div>
</template>

<script>
import * as base64 from 'base-64'
import CryptoJs from 'crypto-js'

export default {
  data() {
    return {
      user: {
        id: "emmmm",
        state: "0",
        //用户的得分？答对加一分
        score: 0
      },
      filmName: "肖申克的救赎",
      userMessage: "",
      //好像是存放历次交流的记录，有用户发送的，也有api返回的，用于显示在聊天框中
      allMessage: [
        { role: "assistant", content: "准备好请回复「开始」" },
      ],
      requestObj: {
        APPID: 'bb5745b1',
        APISecret: 'YTA0MGE2Y2EyZjk1NmExNmJlMGVhYjJl',
        APIKey: 'a666354e968046355a6382826ef35eec',
        Uid: "",
        sparkResult: ""
      },
      isAnswering: false,
      //api返回的答案
      allQustion: [],
      //answer表示正确答案，A、B、C、D
      answer: "",
      qustion: "",
      //表示当前是第一次用户回答还是第二次
      flag: 0,
      movieQuestionForm: {
        analysis: "",
        answer: 0,
        optionA: "",
        optionB: "",
        optionC: "",
        optionD: "",
        questionInfo: "",
        toId: 0
      },
      userAnswerForm: {
        answerTime: "2023-08-14T14:24:22.959Z",
        questionId: 0,
        userAnswer: 0
      }
    }
  },
  computed: {},
  props: [
    "movieName",
    "sendRatingQualification"
  ],
  methods: {
    //userMessage用户的输入
    sendMessage(userMessage) {
      if (!userMessage) return
      // 插入数据库，用户答题记录，this.flag == 1说明这次是用户写答案的过程
      if (userMessage == this.answer && this.flag == 1) {
        this.user.score += 1
        if (userMessage == 'A') this.userAnswerForm.userAnswer = 1
        if (userMessage == 'B') this.userAnswerForm.userAnswer = 2
        if (userMessage == 'C') this.userAnswerForm.userAnswer = 3
        if (userMessage == 'D') this.userAnswerForm.userAnswer = 4
        this.request.post(`/question/insertUserAnswer`, this.userAnswerForm).then(res=>{
          if(res.code == 0){
            this.$message.success("添加问题成功")
            //当前问题回答正确后，用户调到另一个电影页面评分，此时该组件中变量存放上一个问题的信息，需要清除
            location.reload()
            return
          }else{
            this.$message.error("添加失败")
            return
          }
        })
      }
      //回答错误
      if(userMessage != this.answer && this.flag == 1){
        this.sendRatingQualification(this.user.state)
        location.reload()
      }
      this.flag = 1
      this.userMessage = ""
      let message = {
        role: "user",
        content: userMessage
      }
      //将message加入全局对话allMessage，显示在聊天框中
      this.updateNewMessage(message)
      let askSpark = `帮我出一道关于电影《${this.movieName}》的剧情问答选择题。并给出正确答案和解析。回答的格式请参考这个例子。只需要1道题。
      问题：XXXXXXXXXXXX？
          A. XXXXXXXXX
          B. XXXXXXXXX
          C. XXXXXXXXX
          D. XXXXXXXXX 
      正确答案：A. XXXXXXXXXX
      解析：XXXXXXX
      `
      this.getQuestion(askSpark)
    },
    updateNewMessage(message) {
      this.allMessage.push(message)
      this.$nextTick(this.scrollToBottom)
    },
    async getQuestion(message) {
      if (!message) return
      //因为问题只有一道，回答之后所有变量又恢复初始状态。所以当allQuestion长度为1时，表示已经出题
      if (this.allQustion.length == 1) {
        //下面这句什么意思
        // this.allMessage = [{ role: "assistant", content: "答题。准备好请回复「开始」" },]
        if (this.user.score == 1) {
          this.user.state = 1
          //此处标记用户拥有评分资格,并返回上级组件，在Detail中
          setTimeout(this.sendRatingQualification(this.user.state), 2000)
          return
        }else{
          this.sendRatingQualification(this.user.state)
          return
        }
      }
      let url = await this.getWebsocketUrl()
      let socket = new WebSocket(url)
      //在这里传入问题模板
      socket.onopen = (event) => {
        let params = {
          "header": {
            "app_id": this.requestObj.APPID,
            "uid": this.user.id
          },
          "parameter": {
            "chat": {
              "domain": "generalv3.5",
              "temperature": 0.5,
              "max_tokens": 1024,
            }
          },
          "payload": {
            "message": {
              "text": [
                { "role": "user", "content": message },
              ]
            }
          }
        };
        socket.send(JSON.stringify(params))
      }
      socket.onmessage = (event) => {
        //api返回的信息是一轮一轮的，data是每一轮的中间信息
        let data = JSON.parse(event.data)
        //电影名称非法
        if (data.header.code == 10013){
          socket.close()
          this.$message.warning("非常抱歉，根据相关法律法规，我们无法提供关于以下内容的答案")
          //@TODO 这里延迟执行有些问题
          setTimeout(location.reload(),1000)
          return
        }
        console.log("sssssssss",data)
        this.requestObj.sparkResult += data.payload.choices.text[0].content;
        if (data.header.code !== 0) {
          socket.close()
        }
        if (data.header.code === 0) {
          //说明此时到了
          if (data.payload.choices.text && data.header.status === 2) {
            //将返回信息中的答案去除
            let question = this.reset(this.requestObj.sparkResult)
            let questionWithOutAnalysis = this.OutAnalysis(question)
            let answer = this.getAnswer(this.requestObj.sparkResult)
            console.log("正确答案：" + answer)
            this.answer = answer
            this.allQustion.push(question)
            let newMessage = {
              role: "assistant",
              content: questionWithOutAnalysis
            }
            this.updateNewMessage(newMessage)
            this.requestObj.sparkResult = ""
            this.movieQuestionForm.questionInfo = this.getQuestionInfo(question)
            this.movieQuestionForm.analysis = this.getAnalysis(question)
            this.setOptions(question)
            if (answer == 'A') this.movieQuestionForm.answer = 1
            if (answer == 'B') this.movieQuestionForm.answer = 2
            if (answer == 'C') this.movieQuestionForm.answer = 3
            if (answer == 'D') this.movieQuestionForm.answer = 4
            this.movieQuestionForm.toId = this.$route.query.movieId
            this.request.post(`/question/insertMovieQuestions`, this.movieQuestionForm).then(res => {
              if (res.code == 0) {
                this.userAnswerForm.questionId = res.data
              } else {
                this.$message.error(res.message)
              }
            })
            socket.close()
          }
        }
      }
      socket.onerror = (event) => {
        console.log("发送错误")
      }
    },
    //将返回信息中的答案去除
    reset(str) {
      let regex = /正确答案(.*)/
      let result = str.replace(regex, '')
      //为了在html展示跨行，将\n转化为标签
      result = result.replace(/\n/g, "<br>")
      return result
    },
    //利用正则表达式，从返回的信息中获取正确答案
    getAnswer(str) {
      // return str
      let regex = /正确答案(.*)/
      let result = str.match(regex)
      let a = /[ABCD]/g
      let answer = result[1].match(a)
      return answer[0]
    },
    //获取问题解析
    getAnalysis(str){
      let regex = /解析：(.*)/
      let result = str.match(regex)
      return result[1]
    },
    //问题内容
    getQuestionInfo(str){
      let regex = /问题：(.*?)\？/
      let result = str.match(regex)
      return result[1]

    },
    OutAnalysis(str){
      let regex = /解析：(.*)/
      let result = str.replace(regex, '')
      //为了在html展示跨行，将\n转化为标签
      return result
    },
    setOptions(str){
      let regexA = /A.(.*?)<br>/
      let regexB = /B.(.*?)<br>/
      let regexC = /C.(.*?)<br>/
      let regexD = /D.(.*?)<br>/
      this.movieQuestionForm.optionA = str.match(regexA)[1]
      this.movieQuestionForm.optionB = str.match(regexB)[1]
      this.movieQuestionForm.optionC = str.match(regexC)[1]
      this.movieQuestionForm.optionD = str.match(regexD)[1]
    },
    getWebsocketUrl() {
      return new Promise((resovle, reject) => {
        let url = "wss://spark-api.xf-yun.com/v1/x1";
        let host = "spark-api.xf-yun.com";
        let apiKeyName = "api_key";
        let date = new Date().toGMTString();
        let algorithm = "hmac-sha256"
        let headers = "host date request-line";
        let signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v3.5/chat HTTP/1.1`;
        let signatureSha = CryptoJs.HmacSHA256(signatureOrigin, this.requestObj.APISecret);
        let signature = CryptoJs.enc.Base64.stringify(signatureSha);

        let authorizationOrigin = `${apiKeyName}="${this.requestObj.APIKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;

        let authorization = base64.encode(authorizationOrigin);

        // 将空格编码
        url = `${url}?authorization=${authorization}&date=${encodeURI(date)}&host=${host}`;

        resovle(url)
      })
    },
    scrollToBottom() {
      this.$refs.chatWindow.scrollTop = Number.MAX_SAFE_INTEGER
    },
  },
}
</script>

<style>
.chat-box {
  width: 100%;
  height: 100%;

  padding: 10px;
  display: flex;
  flex-direction: column;
}

.chat-window {
  flex: 12;
  overflow-y: auto;

  display: flex;
  flex-direction: column;
  align-items: center;
}

.chat-window>:nth-child(n) {
  margin-bottom: 20px;
}

.message-cell {
  display: flex;
  width: 100%;
  /*height: 60px;*/
}

.message-cell>:nth-child(n) {
  margin: 5px;
}

.avator-box {
  flex: 1;
  display: flex;
  justify-content: center;
  /*align-items: center;*/
}

.avator {
  width: 35px;
  height: 35px;
  border-radius: 50%;
}

.user-avator {
  background-image: radial-gradient(circle at right, #0C7BB3, #F2BAE8);

}

.assistant-avator {
  background-image: radial-gradient(circle at left, #EEBD89, #DE3ABD);
}

.message-text {
  flex: 8;
  padding: 10px;
  display: flex;
  align-items: center;
  border-radius: 2px;
  background-color: rgba(148, 163, 184, .15);
}

.footer {
  flex: 1;

  display: flex;
}

.message-input {
  flex: 4;
  margin-right: 10px;
  border: none;
  padding: 10px;
  background-color: rgba(148, 163, 184, .15);
}

.message-input:focus {
  outline: none;
  background-color: rgba(148, 163, 184, .25);
}

.send-button {
  flex: 1;
  border: none;
  background-color: rgba(148, 163, 184, .15);
  font-size: 16px;
}

.send-button:active {
  background-color: rgba(148, 163, 184, .25);

}
</style>